from django.shortcuts import render, redirect, reverse
from .forms import LoginForm, RegisterForm, GradeForm, CourseForm, ResourceForm, GradeStudentForm
from django.views.generic import View
from django.contrib.auth import login, authenticate, logout
from django.contrib import messages
from utils.mixin_utils import LoginRequiredMixin
from users.models import UserProfile
from django.contrib.auth.hashers import make_password
from users.models import Grade
from course.models import Course, Lesson, Video
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger
from django.http import HttpResponse, HttpResponseForbidden
from django.forms.models import model_to_dict
from django.shortcuts import get_object_or_404
from course.models import Resource, PaperList, Question, Paper
from users.models import GradeStudent
from operation.models import UserScore, UserAnswerLog, Sign, SignUser
from .forms import LessonForm, VideoForm
from notifications.signals import notify
from .forms import MessageForm, ExamForm, SignForm
from notifications.models import Notification
from django.db.models import Count, F
import numpy as np


class LoginView(View):
    @staticmethod
    def get(request):
        login_form = LoginForm()
        return render(request, template_name="login.html", context={"login_form": login_form})

    @staticmethod
    def post(request):
        login_form = LoginForm(request.POST)
        if login_form.is_valid():
            username = login_form.data.get("username")
            password = login_form.data.get("password")
            user = authenticate(username=username, password=password)
            if not user:
                # 闪现一条消息
                messages.error(request, '用户名或密码错误')
            else:
                print(user.usertype)
                if user.usertype != "teacher":
                    messages.error(request, '用户不是老师')
                else:
                    login(request, user)
                    next_url = request.GET.get("next") or reverse("teacher:index")
                    return redirect(next_url)
        return render(request, template_name="login.html", context={"login_form": login_form})


class LogoutView(View):
    @staticmethod
    def get(request):
        logout(request)
        return redirect(reverse("teacher:login"))


class RegisterView(View):
    @staticmethod
    def get(request):
        register_form = RegisterForm()
        return render(request, "register.html", context={"register_form": register_form})

    @staticmethod
    def post(request):
        register_form = RegisterForm(request.POST)
        if register_form.is_valid():
            u = UserProfile(is_staff=False, usertype="teacher")
            u.username = register_form.data.get("username")
            u.password = make_password(register_form.data.get("password"))
            u.email = register_form.data.get("email")
            u.mobile = register_form.data.get("mobile")
            u.save()
            login(request, u)
            return redirect(reverse("teacher:index"))
        return render(request, "register.html", context={"register_form": register_form})


class GradeView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        q = request.GET.get('q', None)
        if q:
            objects = Grade.objects.filter(teacher=request.user, GradeName__icontains=q)
        else:
            objects = Grade.objects.filter(teacher=request.user)
        p = Paginator(object_list=objects, request=request, per_page=5)
        grads = p.page(page)
        return render(request, "index.html", context={"grades": grads, "keyword": q})


class AddGradeView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        form = GradeForm()
        return render(request, "add_grade.html", context={"form": form})

    @staticmethod
    def post(request):
        form = GradeForm(request.POST)
        if form.is_valid():
            grade_name = form.data.get("grade_name")
            g = Grade()
            g.teacher = request.user
            g.GradeName = grade_name
            g.save()
            messages.info(request, '添加班级成功')
            return redirect(reverse("teacher:index"))
        return render(request, "add_grade.html", context={"form": form})


class DeleteGrade(LoginRequiredMixin, View):
    @staticmethod
    def get(request, grade):
        g = Grade.objects.filter(id=grade, teacher=request.user)
        if g:
            messages.info(request, '删除{}班级成功'.format(g.first().GradeName))
            g.delete()
        else:
            messages.info(request, '删除班级失败')
        return redirect(reverse("teacher:index"))


class CourseListView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        q = request.GET.get('q', None)
        grade_id = Grade.objects.filter(teacher=request.user).values_list("id")
        if q:
            objects = Course.objects.filter(grade_id__in=grade_id, name__icontains=q)
        else:
            objects = Course.objects.filter(grade_id__in=grade_id)
        p = Paginator(object_list=objects, request=request, per_page=5)
        courses = p.page(page)
        return render(request, "course_list.html", context={"courses": courses, "keyword": q})


class AddCourseView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        course_form = CourseForm(user=request.user)
        return render(request, "add_course.html", context={"course_form": course_form})

    @staticmethod
    def post(request):
        print(request.POST)
        print(request.FILES)
        course_form = CourseForm(request.user, request.POST, request.FILES)
        if course_form.is_valid():
            c = Course()
            print(course_form.data)
            c.name = course_form.data.get("name")
            c.teacher = request.user
            c.grade_id = course_form.data.get("grade")
            c.fav_nums = course_form.data.get("fav_nums")
            c.detail = course_form.data.get("detail")
            c.desc = course_form.data.get("desc")
            c.image.save(request.FILES.get("image").name, request.FILES.get("image"), save=True)
            c.students = course_form.data.get("students")
            c.click_nums = course_form.data.get("click_nums")
            c.learn_times = course_form.data.get("learn_times")
            c.tag = course_form.data.get("tag")
            c.teacher_tell = course_form.data.get("teacher_tell")
            c.you_need_know = course_form.data.get("you_need_know")
            c.save()
            messages.info(request, "添加成功")
        return render(request, "add_course.html", context={"course_form": course_form})


class DetailCourseView(LoginRequiredMixin, View):

    @staticmethod
    def get(request, course_id):
        course = get_object_or_404(Course, id=course_id)
        if course.grade.teacher == request.user:
            data = model_to_dict(course)
            course_form = CourseForm(request.user, data, {"image": course.image})
            print(course_form)
            return render(request, "course_detail.html", context={"course_form": course_form})
        else:
            return HttpResponse(status=403)

    @staticmethod
    def post(request, course_id):
        course_form = CourseForm(request.user, request.POST, request.FILES)
        data = course_form.data.copy()
        data.pop("csrfmiddlewaretoken")
        data = {key: value for key, value in data.items()}
        course = get_object_or_404(Course, id=course_id)
        if course.grade.teacher == request.user:
            course.__dict__.update(**data)
            course.image.save(request.FILES.get("image").name, request.FILES.get("image"), save=True)
            course.save()
            messages.info(request, "修改课程信息成功")
            return render(request, "course_detail.html", context={"course_form": course_form})
        else:
            return HttpResponse(status=403)


class DeleteCourseView(LoginRequiredMixin, View):
    @staticmethod
    def get(request, course_id):
        course = get_object_or_404(Course, id=course_id)
        if course.grade.teacher == request.user:

            messages.info(request, "删除{}课程成功".format(course_id))
            Course.objects.filter(id=course_id).delete()
            return redirect(reverse("teacher:course_list"))
        else:
            return HttpResponse(status=403)


class ResourceView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        objects = Resource.objects.filter(course__grade__teacher=request.user)
        p = Paginator(object_list=objects, request=request, per_page=5)
        resources = p.page(page)
        return render(request, "resources_list.html", context={"resources": resources})


class AddResourceView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        form = ResourceForm(user=request.user)
        return render(request, "add_resoure.html", context={"form": form})

    @staticmethod
    def post(request):
        form = ResourceForm(request.user, request.POST, request.FILES)
        if form.is_valid():
            if not Resource.objects.filter(course_id=form.data.get("course")):
                messages.info(request, "添加成功")
                resource = Resource()
                resource.course_id = form.data.get("course")
                resource.name = form.data.get("name")
                resource.downloads.save(request.FILES.get("downloads").name, request.FILES.get("downloads"), save=True)
                resource.save()
            else:
                messages.error(request, "一个课程只能添加一个资料")
        return render(request, "add_resoure.html", context={"form": form})


class DeleteResourceView(LoginRequiredMixin, View):
    @staticmethod
    def get(request, resource_id):
        resource = get_object_or_404(Resource, id=resource_id, course__grade__teacher=request.user)
        print(resource)
        resource.delete()
        messages.info(request, "删除成功")
        return redirect(reverse("teacher:resource_list"))


class GradeStudentsView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        objects = GradeStudent.objects.filter(grade__teacher=request.user)
        p = Paginator(object_list=objects, request=request, per_page=5)
        students = p.page(page)
        return render(request, "students_list.html", context={"students": students})


class AddGradeStudentsView(LoginRequiredMixin, View):

    @staticmethod
    def get(request):
        form = GradeStudentForm(user=request.user)
        return render(request, "add_student.html", context={"form": form})

    @staticmethod
    def post(request):
        form = GradeStudentForm(request.user, request.POST)
        if form.is_valid():
            messages.info(request, "添加成功")
            g = GradeStudent()
            g.user = UserProfile.objects.filter(username=form.data.get("user")).first()
            g.grade_id = form.data.get("grade")
            g.save()
        return render(request, "add_student.html", context={"form": form})


class DeleteStudentsView(LoginRequiredMixin, View):
    @staticmethod
    def get(request, student_id):
        messages.info(request, "删除成功")
        g = get_object_or_404(GradeStudent, id=student_id, grade__teacher=request.user)
        g.delete()
        return redirect(reverse("teacher:students"))


class LessonView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")
        if keyword:
            objects = Lesson.objects.filter(name__icontains=keyword, course__grade__teacher=request.user)
        else:
            objects = Lesson.objects.filter(course__grade__teacher=request.user)
        p = Paginator(object_list=objects, request=request, per_page=5)
        lessons = p.page(page)
        return render(request, "lesson_list.html", context={"lessons": lessons, "keyword": keyword})


class AddLessonView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        form = LessonForm(request.user)
        return render(request, "add_lesson.html", context={"form": form})

    @staticmethod
    def post(request):
        form = LessonForm(request.user, request.POST)
        print(form.errors)
        if form.is_valid():
            l = Lesson()
            l.course = Course.objects.get(id=form.data.get("course"))
            l.name = form.data.get("name")
            l.save()
            messages.info(request, "添加章节成功")
        return render(request, "add_lesson.html", context={"form": form})


class DeleteLessonView(LoginRequiredMixin, View):
    @staticmethod
    def get(request, lesson_id):
        print(lesson_id)
        l = get_object_or_404(Lesson, course__grade__teacher=request.user, id=lesson_id)
        l.delete()
        messages.info(request, "删除成功")
        return redirect(reverse("teacher:lesson_list"))


class VideoView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        grade_ids = Grade.objects.filter(teacher=request.user).values_list("id")
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")
        if keyword:
            objects = Video.objects.filter(lesson__course__grade_id__in=grade_ids, name__icontains=keyword)
        else:
            objects = Video.objects.filter(lesson__course__grade_id__in=grade_ids)
        p = Paginator(object_list=objects, request=request, per_page=5)
        videos = p.page(page)
        return render(request, "video_list.html", context={"videos": videos, "keyword": keyword})


class AddVideoView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        form = VideoForm(user=request.user)
        return render(request, "add_video.html", context={"form": form})

    @staticmethod
    def post(request):
        form = VideoForm(request.user, request.POST)
        if form.is_valid():
            messages.info(request, "添加视频成功")
            v = Video()
            v.name = form.data.get("name")
            v.url = form.data.get("url")
            v.learn_times = form.data.get("learn_times")
            v.lesson = Lesson.objects.get(id=form.data.get("lesson"))
            v.save()
        return render(request, "add_video.html", context={"form": form})


class DeleteVideoView(LoginRequiredMixin, View):
    @staticmethod
    def get(request, video_id):
        grade_ids = Grade.objects.filter(teacher=request.user).values_list("id")
        video = get_object_or_404(Video, lesson__course__grade_id__in=grade_ids, id=video_id)
        video.delete()
        messages.info(request, "删除成功")
        return redirect(reverse("teacher:video_list"))


class MessageView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")

        user = request.user.id
        if keyword:
            objects = Notification.objects.filter(actor_object_id=user, verb__icontains=keyword)
        else:
            objects = Notification.objects.filter(actor_object_id=user)
        p = Paginator(object_list=objects, request=request, per_page=10)
        ms = p.page(page)
        return render(request, "message_list.html", context={"ms": ms, "keyword": keyword})


class SendMessageView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        form = MessageForm(request.user)
        return render(request, "add_message.html", context={"form": form})

    @staticmethod
    def post(request):
        form = MessageForm(request.user, request.POST)
        if form.is_valid():
            messages.info(request, "发送消息成功")
            users = [i.user for i in
                     GradeStudent.objects.filter(grade_id=form.data.get("grade"), grade__teacher=request.user)]
            grade = Grade.objects.get(id=form.data.get("grade"))
            notify.send(request.user, recipient=users, verb=form.data.get("title"),
                        description=form.data.get("content"), target=grade)
        return render(request, "add_message.html", context={"form": form})


class CreateExamView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        form = ExamForm(user=request.user)
        return render(request, "create_exame.html", context={"form": form})

    @staticmethod
    def post(request):
        form = ExamForm(request.user, request.POST)
        if form.is_valid():
            pl = PaperList(name=form.data.get("name"), course_id=form.data.get("course"))
            pl.save()
            qs = Question.objects.filter(course__grade__teacher=request.user).order_by('?')[:10]
            papers = [Paper(course=Course.objects.get(id=form.data.get("course")), question=q, paper_name=pl) for q in
                      qs]
            Paper.objects.bulk_create(papers)
            messages.info(request, "创建考试成功")
        return render(request, "create_exame.html", context={"form": form})


class ListExamView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")
        if keyword:
            objects = PaperList.objects.filter(course__grade__teacher=request.user, name__icontains=keyword)
        else:
            objects = PaperList.objects.filter(course__grade__teacher=request.user, )

        p = Paginator(object_list=objects, request=request, per_page=10)
        PaperLists = p.page(page)
        print(PaperLists.object_list)

        return render(request, "exame_list.html", context={"PaperLists": PaperLists, "keyword": keyword})


class ExamQuestionDetail(LoginRequiredMixin, View):
    @staticmethod
    def get(request, exam_id):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")
        if keyword:
            objects = Paper.objects.filter(course__grade__teacher=request.user, paper_name=exam_id,
                                           question__content__icontains=keyword)
        else:
            objects = Paper.objects.filter(course__grade__teacher=request.user, paper_name=exam_id)
        p = Paginator(object_list=objects, request=request, per_page=10)
        questions = p.page(page)
        return render(request, "exam_detail.html", context={"questions": questions, "keyword": keyword})


class ActiveExam(LoginRequiredMixin, View):
    @staticmethod
    def get(request, exam_id):
        p = PaperList.objects.get(id=exam_id)
        p.is_allow = False if p.is_allow == True else True
        p.save()
        return redirect(reverse("teacher:list_exam"))


class UserAnalyseView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")
        if keyword:
            objects = PaperList.objects.filter(course__grade__teacher=request.user, name__icontains=keyword)
        else:
            objects = PaperList.objects.filter(course__grade__teacher=request.user, )

        p = Paginator(object_list=objects, request=request, per_page=10)
        PaperLists = p.page(page)
        print(PaperLists.object_list)
        return render(request, "score_analyse.html", context={"PaperLists": PaperLists, "keyword": keyword})


class PaperScoreDetail(LoginRequiredMixin, View):
    @staticmethod
    def get(request, exam_id):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")
        if keyword:
            objects = UserScore.objects.filter(paper_id=exam_id, user__username__icontains=keyword).order_by("-total")
        else:
            objects = UserScore.objects.filter(paper_id=exam_id).order_by("-total")
        sum = objects.count()
        p = Paginator(object_list=objects, request=request, per_page=10)
        user_scores = p.page(page)
        return render(request, "paperScoreDetail.html",
                      context={"user_scores": user_scores, "keyword": keyword, "sum": sum})


class UserQuestionDetailView(LoginRequiredMixin, View):
    @staticmethod
    def get(request, user_id, exam_id):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")
        if keyword:
            objects = UserAnswerLog.objects.filter(user_id=user_id, paper__paper_name_id=exam_id,
                                                   paper__question__content__icontains=keyword)
        else:
            objects = UserAnswerLog.objects.filter(user_id=user_id, paper__paper_name_id=exam_id)
        p = Paginator(object_list=objects, request=request, per_page=10)
        answer_log = p.page(page)
        return render(request, "answerlog.html", context={"answer_log": answer_log, "keyword": keyword})


class ExamAnalyseView(LoginRequiredMixin, View):
    @staticmethod
    def get(request, paper_id):
        all_user_score = UserScore.objects.filter(paper_id=paper_id).order_by("-total")
        top_user = all_user_score[:10]  # 成绩排名前十的用户
        user_name = [i.user.username for i in top_user]
        user_score = [i.total for i in top_user]
        scores = all_user_score.values("total").annotate(number=Count("total"))  # 成绩统计
        scores = [{"value": i.get("number"), "name": "{} 分".format(i.get("total"))} for i in scores]

        user_answer_log = UserAnswerLog.objects.filter(paper__paper_name_id=paper_id,
                                                       paper__question__score__gt=F("score"))
        answer_analyse_dict = {}
        for i in user_answer_log:
            if i.paper.question.content in answer_analyse_dict:
                answer_analyse_dict[i.paper.question.content] += 1
            else:
                answer_analyse_dict[i.paper.question.content] = 1
        answer_analyse_dict = [{"name":key,"value":value}for key,value in answer_analyse_dict.items()]
        score_data = all_user_score.values_list("total")
        np.set_printoptions(precision=4)
        score_mean = np.mean(score_data)# 平均值
        score_var = np.var(score_data)# 方差
        score_median = np.median(score_data)#中位数
        score_max = max(score_data)[0]
        score_min = min(score_data)[0]


        return render(request, "exam_analyese.html"
                      ,context={"user_name": user_name,
                                 "user_score": user_score,
                                 "scores": scores,
                                "answer_analyse_dict":answer_analyse_dict,
                                "score_mean":score_mean,
                                "score_var":score_var,
                                "score_max":score_max,
                                "score_min":score_min,
                                "score_median":score_median
                                 })


class CreateSignView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        sign_form = SignForm(user=request.user)
        return render(request, "add_sign.html", context={"form": sign_form})

    @staticmethod
    def post(request):
        sign_form = SignForm(request.user, request.POST)
        if sign_form.is_valid():
            s = Sign(sign_name=sign_form.data.get("name"), grade_id=sign_form.data.get("grade"))
            s.save()
            messages.info(request, "签到创建成功")
            return redirect(reverse("teacher:sign_list"))
        return render(request, "add_sign.html", context={"form": sign_form})


class ListSignView(LoginRequiredMixin, View):
    @staticmethod
    def get(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        keyword = request.GET.get("q")
        if keyword:
            objects = Sign.objects.filter(sign_name__icontains=keyword, grade__in=request.user.grade.all())
        else:
            objects = Sign.objects.filter(grade__in=request.user.grade.all())
        p = Paginator(object_list=objects, request=request, per_page=10)
        sign_list = p.page(page)
        return render(request, "sign_list.html", context={"sign_list": sign_list, "keyword": keyword})


class SignDetailView(LoginRequiredMixin, View):
    @staticmethod
    def get(request, sign_id):
        s = Sign.objects.get(id=sign_id)
        su = {i.students.id: i for i in SignUser.objects.filter(sign=s)}

        students = s.grade.GradeStudent.all()
        students_dict = [{"name": student.user.username, "id": student.user.id, "is_sign": su.get(student.user.id)} for
                         student in students]
        return render(request, "signdetail.html", context={"students_sum": len(students),
                                                           "sign_sum": len(su), "students": students_dict})
